// 
//  GFWInterceptorLibrary.mm
//  GFWInterceptor
//  
//  Created by Chen Zhang on 2010-06-24.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
// 


#import "GFWInterceptorLibrary.h"
#import <CFNetwork/CFNetwork.h>

extern NSMutableArray *keywordlist;

BOOL isPicFBServer(NSString *urlstring){
    if(urlstring == nil) return NO;
    NSArray *keywordlist = [NSArray arrayWithObjects:@"facebook", @"twitpic", @"img.ly", @"tweet", @"yfrog", @"foursquare",nil];
    for(NSString *keyword in keywordlist){
        if([urlstring rangeOfString:keyword options:NSCaseInsensitiveSearch].location != NSNotFound){
            return YES;
        }
    }
    return NO;
}



NSString *forwardURL(NSURL *theURL){
    NSURL *newURL = theURL;
    NSString *urlstring = [newURL host];
    NSString *schemestr = [newURL scheme];
    if([schemestr rangeOfString:@"http" options:NSCaseInsensitiveSearch].location == NSNotFound)
        return nil;
    
    for (NSString *keyword in keywordlist)
    {
      if(keyword != nil && [urlstring rangeOfString:keyword options:NSCaseInsensitiveSearch].location != NSNotFound){
          if(ignorehttps && [schemestr isEqualToString:@"https"])
              continue; //let https go, else we take it seriously          
          return [NSString stringWithFormat:@"%@/%@?zctimetag=%d",isPicFBServer(urlstring) ? picfbproxy : apiproxy,[newURL path],(int)[NSDate timeIntervalSinceReferenceDate]];  //forware to a whole new world         
      } 
    }
    return nil;
}


//here we use MSHookFunction to hook to CFNetwork Methods
static CFHTTPMessageRef (*original_CFHTTPMessageCreateRequest)(CFAllocatorRef alloc, CFStringRef requestMethod, CFURLRef url, CFStringRef httpVersion);  

CFHTTPMessageRef replaced_CFHTTPMessageCreateRequest(CFAllocatorRef alloc, CFStringRef requestMethod, CFURLRef url, CFStringRef httpVersion){
    //save a copy of old url
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSString *originalString = [[NSString alloc] initWithString:[(NSURL *)url absoluteString]];
    NSString *newstr;
    
    #ifdef DEBUG
    NSLog(@"CFNetwork We have intercepted this string: %@",originalString);
    #endif
    
    newstr = forwardURL((NSURL *)url);
    CFHTTPMessageRef result;
    if(newstr == nil){
        result = original_CFHTTPMessageCreateRequest(alloc,requestMethod, url,httpVersion);
        [pool release];
        return result;
    }
    else{
        CFURLRef newurl = (CFURLRef)[[NSURL alloc] initWithString:newstr];
        CFHTTPMessageRef originalmessage = original_CFHTTPMessageCreateRequest(alloc,requestMethod,newurl,httpVersion);
        //set headers
        CFHTTPMessageSetHeaderFieldValue(originalmessage,(CFStringRef)@"zcreal-nsurl",(CFStringRef)originalString);
        #ifdef DEBUG
        NSLog(@"header for zcreal-nsurl %@",CFHTTPMessageCopyHeaderFieldValue(originalmessage,(CFStringRef)@"zcreal-nsurl"));
        #endif
        
        [pool release];
        return originalmessage;
    }
}


static CFURLRef (*original_CFHTTPMessageCopyRequestURL)(CFHTTPMessageRef request);

CFURLRef replaced_CFHTTPMessageCopyRequestURL(CFHTTPMessageRef request){
    //some one try to copy my modified url
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    #ifdef DEBUG
    NSLog(@"someone try to copy my modified url, return our original copy");
    #endif
    
    // CFURLRef originalurl = original_CFHTTPMessageCopyRequestURL(request);
    // if (originalurl == NULL){
    //     #ifdef DEBUG
    //     NSLog(@"not feeling well");
    //     #endif
    //     
    //     [pool release];
    //     return originalurl;
    // }
    
    CFStringRef modifiedurl = CFHTTPMessageCopyHeaderFieldValue(request, (CFStringRef)@"zcreal-nsurl");
    
    #ifdef DEBUG
    if(modifiedurl != NULL)
        NSLog(@"return something we already know, original url %@", (NSString *)modifiedurl);
    #endif
    
    if(modifiedurl){
        CFURLRef modifiedurlcopy = (CFURLRef)[[NSURL alloc] initWithString:(NSString *)modifiedurl];
        [pool release];
        return modifiedurlcopy;
    }
    [pool release];
    return original_CFHTTPMessageCopyRequestURL(request);;
}



extern "C" void GFWInterceptorInitialize() {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];    
    NSString *identifier = [[NSBundle mainBundle] bundleIdentifier];

    #ifdef DEBUG
    NSLog(@"out side init: %@",identifier);
    #endif

    if (identifier != nil && [identifier rangeOfString:@".apple."].location == NSNotFound) {
    // if (YES) {
	    #ifdef DEBUG
        NSLog(@"init GFWInterceptor");
        #endif 

        NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.overboming.gfwinterceptor.plist"];
        if(!prefs){
            prefs = [[NSMutableDictionary alloc] init];
            #ifdef DEBUG
            NSLog(@"Dictionary not found!");
            #endif 
        } 
        BOOL enabled = [prefs objectForKey:@"isenabled"] ? [[prefs objectForKey:@"isenabled"] boolValue] : YES;
        
        if (!enabled){

	    #ifdef DEBUG
        NSLog(@"not enabled, return");
        #endif 
            
            [pool release];
            return;
        }
        
        apiproxy = [prefs objectForKey:@"apiproxy"] ? [prefs objectForKey:@"apiproxy"] : @"http://waytosing.appspot.com";
        picfbproxy = [prefs objectForKey:@"picfbproxy"] ? [prefs objectForKey:@"picfbproxy"] : @"http://waytosing.appspot.com";
        
        ignorehttps = [prefs objectForKey:@"ignorehttps"] ? [[prefs objectForKey:@"ignorehttps"] boolValue] : NO;
        keywordlist = [[NSMutableArray alloc] initWithCapacity:12];
        int i;
        for(i = 1; i <= NUM_OF_KEYWORDS; i ++){
            NSString *keyword = [prefs objectForKey:[NSString stringWithFormat:@"%@%d",@"keyword",i]];
            NSString *trimmedString = [keyword stringByTrimmingCharactersInSet:
                                              [NSCharacterSet whitespaceAndNewlineCharacterSet]];
           #ifdef DEBUG
           NSLog(@"keyword %@",trimmedString);        
           #endif
            if(trimmedString != nil && [trimmedString length] != 0){
                [keywordlist addObject:keyword];
            }
        }
    
        MSHookFunction(CFHTTPMessageCreateRequest,replaced_CFHTTPMessageCreateRequest, &original_CFHTTPMessageCreateRequest);
        // MSHookFunction(CFHTTPMessageCopyRequestURL,replaced_CFHTTPMessageCopyRequestURL, &original_CFHTTPMessageCopyRequestURL);
	}
    [pool release];
}
